package OneSpring.IOC;

import OneSpring.Annotation.Auto;
import OneSpring.Annotation.Beans;
import OneSpring.Annotation.MyComponent;
import OneSpring.Annotation.Scope;
import OneSpring.Component.BeanClassDefinition;
import org.apache.commons.lang.StringUtils;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;

public class MyIOC {
    private Class aClass ;
    private ConcurrentHashMap<String,BeanClassDefinition> DefinitionMap = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String,Object> singleMap = new ConcurrentHashMap<>();
    public MyIOC(){

    }
    public MyIOC(Class t){
        createBeans(t);
        Enumeration<String> keys = DefinitionMap.keys();
        while (keys.hasMoreElements()){
            String beanName = keys.nextElement();
            BeanClassDefinition beanClassDefinition = DefinitionMap.get(beanName);
            if ("single".equals(beanClassDefinition.getScope())){
                Object create = Create(beanClassDefinition, beanName);
                singleMap.put(beanName,create);
            }

        }
    }


    private void createBeans(Class t){
        this.aClass = t;

        ClassLoader classLoader = MyIOC.class.getClassLoader();
        Beans d = (Beans) t.getDeclaredAnnotation(Beans.class);
        String path = d.value();

        path = path.replace(".","/");

        URL url = classLoader.getResource(path);

        File files = new File(url.getFile());
        if (files.isDirectory()){
            File[] files1 = files.listFiles();
            for (File file :files1) {
                String absolutePath = file.getAbsolutePath();

                if (absolutePath.endsWith(".class")){
                    String name = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1,absolutePath.indexOf(".class"));
                   path = path.replace("/",".");
                   name = path + "." + name;

                    try {
                        Class<?> tClass = Class.forName(name);
                        if (tClass.isAnnotationPresent(MyComponent.class)){
                            String scope  = "single";
                            if (tClass.isAnnotationPresent(Scope.class)){
                                Scope declaredAnnotation = tClass.getDeclaredAnnotation(Scope.class);
                                scope = declaredAnnotation.value();
                            }
                            name = name.substring(name.lastIndexOf(".")+1);
                            String beanName = StringUtils.uncapitalize(name);
                            MyComponent declaredAnnotation = tClass.getDeclaredAnnotation(MyComponent.class);
                            if (!"".equals(declaredAnnotation.value())){
                                beanName = declaredAnnotation.value();
                            }
                            BeanClassDefinition beanClassDefinition = new BeanClassDefinition();
                            beanClassDefinition.setaClass(tClass);
                            beanClassDefinition.setScope(scope);
                            DefinitionMap.put(beanName,beanClassDefinition);
                        }


                    } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                    }    finally {
                    }


                }


            }

        }





    }

    public Object getBean(String name){
        BeanClassDefinition beanClassDefinition = DefinitionMap.get(name);
        if (beanClassDefinition == null){
            throw new RuntimeException();
        }
        String scope = beanClassDefinition.getScope();
        if ("single".equals(scope)){
            return singleMap.get(name);
        }else {
            return Create(beanClassDefinition,name);
        }


    }
    private Object Create(BeanClassDefinition beanClassDefinition ,String name){
        Class tClass = beanClassDefinition.getaClass();
       Object o =null;
        try {
            o = tClass.getDeclaredConstructor().newInstance();
            Field[] fields = tClass.getDeclaredFields();
            for (Field field :fields) {
                if (field.isAnnotationPresent(Auto.class)){

                    Auto annotation = (Auto) field.getAnnotation(Auto.class);
                    boolean quire = annotation.quire();
                    if (quire){
                        String fieldName = field.getName();
                        Object bean = getBean(fieldName);
                        field.setAccessible(true);
                        field.set(o,bean);
                    }
                }
            }


        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } finally {
        }
        return o;
    }


}
